home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tricks of the Mac Game Programming Gurus
/
TricksOfTheMacGameProgrammingGurus.iso
/
More Source
/
C⁄C++
/
Xconq 7.0d37
/
source
/
libcurses
/
v_maccur.c
< prev
next >
Wrap
Text File
|
1995-01-31
|
47KB
|
1,622 lines
/* File v_maccur.c:
* Machine specific part of curses implementation for Macintosh.
* Also includes rudimentary replacements for stdio functions.
*
* Copyright (c) 1994
* by Robert Zimmerman
*
* This code may be included in any work, public or private, with the
* exception of creating a commercial curses-compatible subroutine
* library. (In other words, use the code all you want, but please don't
* rip off the author by reselling this code as your own).
*
*/
#include <AppleEvents.h>
#include <limits.h>
#include <ctype.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include "curses.h"
/****
* Resources expected by this code are:
* An ALRT and DITL to put up alerts with the function maccur_cpu_share (see macro ALERT_RSRC_ID).
* A MENU and MBAR to draw the menu (which includes only the apple menu) (see macro MENU_RES_ID).
*
* Optionally, an ALRT and DITL for the "About x..." menu item (see variable _maccur_about_res_id).
****/
/****
* First some macros for font, screen setup, etc:
****/
#define X_MARGIN 2
#define Y_MARGIN 4
#define Y_PIX_WIN (rowheight_pix * _maccur_lines + Y_MARGIN)
#define X_PIX_WIN (charwid_pix * _maccur_cols + 2 * X_MARGIN)
/****
* ROW/COL_TO_PIX determine pen position to write character at row/col.
* First row/column is 0/0.
****/
#define COL_TO_PIX(col) ((col) * charwid_pix + X_MARGIN)
#define ROW_TO_PIX(row) (((row) + 1) * rowheight_pix)
#define MAX_OUT_STRSEG 132 /* Max number of parts of a single character row (distinguished by writing attrib. */
#define MAX_TYPEAHEAD 32 /* Number of keystrokes that will be buffered. */
#define FLASH_TICKS 8 /* Flash cursor 2x second. */
#define WINDO_TOP_ON_SCREEN 40 /* Default position of window on screen. */
#define WINDO_LEFT_ON_SCREEN 5
#define ALERT_RSRC_ID 128 /* ALRT id for generalize alert. */
#define MENU_RES_ID 128 /* MBAR id for putting up (not much of a) menu. */
#define TST_BIT(i, b) ((i) & (1 << (b)))
#define SET_BIT(b) (1 << (b))
enum {
MACCUR_RETURN_ON_IDLE_BIT,
MACCUR_RETURN_ON_CHAR_BIT
};
typedef struct key_evnt_strct { /* Struct in which to buffer keyboard events. */
long msg;
short mod;
} KEY_EVENT;
static KEY_EVENT typebuf[MAX_TYPEAHEAD]; /* Buffer for keyboard events. */
/****
* The following can be modified before curses is initialized
* in order to customize display, etc:
****/
int _maccur_cols = 80; /* Window will be initialized to this size. */
int _maccur_lines = 25;
char *_maccur_font_name = "Monaco"; /* Font to use (C string). */
int _maccur_font_size = 9; /* Size of font. */
int _maccur_handle_break_option = MACCUR_EXIT_ON_BREAK; /* This determines what happens on CMD-. (see enum in macurses.h). */
int _maccur_about_res_id = 128; /* Resource id alert to display if About... is chosen from apple menu. */
char *_maccur_pgm_name = "Curses"; /* Program name for about and window title. */
int _maccur_fg_sleep_ticks = 1; /* How much can WaitNextEvent sleep in foreground. */
int _maccur_bg_sleep_ticks = 2; /* How much can WaitNextEvent sleep in background. */
int _maccur_io_sleep_dvsr = 1; /* How many of the output calls (maccur_printf, etc) call maccur_cpu_share. */
/* (1/_maccur_io_sleep_dvsr of output calls will call maccur_cpu_share). */
static int rowheight_pix; /* Screen dimensions for each character. */
static int charwid_pix;
static short font_num; /* Writing font number. */
static short font_res_id; /* Font resource ID. */
static int show_cursor_flag; /* TRUE if cursor should be flashed. */
static Rect cursor_rect; /* Cursor, as a Rect. */
static WindowPtr the_windo; /* Program window. */
static long last_flash_when; /* Keep track of when cursor flashed. */
static int in_background_flag; /* Keep track of program foreground/bkground state. */
static int cursor_inverted; /* True if cursor is currently inverted. */
static int typeahead_cnt; /* How many characters are waiting in typebuf. */
static int typeahead_indx; /* Where does next character go in typebuf. */
static int outchar_indx; /* Where does next character come out of typebuf. */
static chtype *screen_char_arry; /* Array holding screen contents. */
static FontInfo fnt_info; /* Description of writing font. */
static int maccur_about_mitm; /* 1 if there is an About... item in apple menu. */
static int maccur_has_menu; /* True if MBAR resource was found and menu put up. */
static int direct_curs_pos_row; /* Keep track of cursor position when in direct (non-curses) mode. */
static int direct_curs_pos_col;
static int cpu_share_rot_cnt; /* When this reaches _maccur_io_sleep_dvsr its time to share CPU. */
/********
**
** maccur_init_toolbox: Initialize mac stuff.
**
**
********/
static void maccur_init_toolbox(void)
{
InitGraf(&thePort);
InitFonts();
FlushEvents(everyEvent, 0);
InitWindows();
InitMenus();
TEInit();
InitDialogs(0L);
InitCursor();
MaxApplZone();
}
/********
**
** event_do_nothing: Do nothing in response to apple events.
**
**
********/
static pascal OSErr event_do_nothing(
const AppleEvent *theAppleEvent,
AppleEvent *reply,
long refCon
) {
return 0;
}
/********
**
** quit_app: Quit application in response to apple event.
** This is fairly severe -- Should put up a dialogue box?
**
**
********/
static pascal OSErr quit_app(
const AppleEvent *theAppleEvent,
AppleEvent *reply,
long refCon
) {
ExitToShell();
return 0;
}
/********
**
** maccur_init_event: Initialize handlers (such as they are) for
** required apple events.
**
**
********/
static void maccur_init_event(void)
{
AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
event_do_nothing, 0L, FALSE);
AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
event_do_nothing, 0L, FALSE);
AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,
event_do_nothing, 0L, FALSE);
AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
quit_app, 0L, FALSE);
}
/********
**
** maccur_get_font_info: Search for resouce for desired font via FOND resource.
** Return dimension of characters for sizing of window. There must be an
** easier way to determine the required window size b4 putting the window
** up (and without putting a fixed size window in resource file).
**
** Returns:
** TRUE if font resource found, else FALSE.
**
**
********/
static int maccur_get_font_info(
char *font_name, /* -R- Name of desired font. */
int font_pts, /* -R- Size of desired font. */
short *font_num_ptr, /* -W- Return font number. */
short *font_id_ptr, /* -W- Return font resource id. */
int *rowheight_pix_ptr, /* -W- Return height of font. */
int *charwid_pix_ptr /* -W- Return width of font. */
) {
ResType res_typ;
Handle rsrc_ptr;
FamRec *fnt_fam_ptr;
FontAssoc *fnt_cnt_ptr;
AsscEntry *fnt_assc_list_ptr;
FontRec *fnt_rec_ptr;
int i;
char buf[256];
memcpy(&res_typ, "FOND", sizeof(res_typ));
if ((rsrc_ptr = GetNamedResource(res_typ, (ConstStr255Param) font_name)) == NULL)
return FALSE;
GetResInfo(rsrc_ptr, font_id_ptr, &res_typ, (unsigned char *) buf);
if (ResError() != noErr) return FALSE;
fnt_fam_ptr = *((FamRec **)rsrc_ptr);
fnt_cnt_ptr = (FontAssoc *)(fnt_fam_ptr + 1);
fnt_assc_list_ptr = (AsscEntry *)(fnt_cnt_ptr + 1);
*font_num_ptr = fnt_fam_ptr->ffFamID;
for (i = 0; i < fnt_cnt_ptr->numAssoc + 1; i++)
{
if ((fnt_assc_list_ptr + i)->fontSize == font_pts &&
(fnt_assc_list_ptr + i)->fontStyle == 0)
break;
}
if (i == fnt_cnt_ptr->numAssoc + 1) return FALSE;
fnt_rec_ptr = NULL;
if ((fnt_assc_list_ptr + i)->fontID == *font_id_ptr * 128 + font_pts)
{
memcpy(&res_typ, "FONT", sizeof(res_typ));
if ((rsrc_ptr = GetResource(res_typ, *font_id_ptr)) != NULL)
fnt_rec_ptr = *((FontRec **)rsrc_ptr);
}
if (fnt_rec_ptr != NULL)
{
memcpy(&res_typ, "NFNT", sizeof(res_typ));
if ((rsrc_ptr = GetResource(res_typ, *font_id_ptr)) != NULL)
fnt_rec_ptr = *((FontRec **)rsrc_ptr);
}
if (fnt_rec_ptr == NULL) return FALSE;
*rowheight_pix_ptr = fnt_rec_ptr->fRectHeight;
*charwid_pix_ptr = fnt_rec_ptr->fRectWidth;
return TRUE;
}
/********
**
** maccur_init_window: Size and open curses window.
**
**
********/
static void maccur_init_window(void)
{
Rect windo_rect;
ResType font_res;
FontRec *fnt_rec_ptr;
Handle rsrc_ptr;
char windo_titl[128], font_name[32];
font_name[0] = strlen(_maccur_font_name); /* Copy font name to local pascal string. */
strcpy(font_name + 1, _maccur_font_name);
if (_maccur_font_size <= 0) _maccur_font_size = 9; /* Make sure font size is reasonable. */
windo_rect.top = WINDO_TOP_ON_SCREEN;
windo_rect.left = WINDO_LEFT_ON_SCREEN;
if (maccur_get_font_info(font_name, _maccur_font_size, /* Try to find font dimensions before putting up window. */
&font_num, &font_res_id,
&rowheight_pix, &charwid_pix))
{
windo_rect.bottom = windo_rect.top + Y_PIX_WIN;
windo_rect.right = windo_rect.left + X_PIX_WIN;
}
else
{
GetFNum((ConstStr255Param) font_name, &font_num); /* If can't find them, put it up and then resize it. */
if (font_num == 0)
{
maccur_alert_msg("Could not access font '%s'!",
_maccur_font_name);
ExitToShell();
}
windo_rect.bottom = windo_rect.top + 10;
windo_rect.right = windo_rect.left + 10;
}
strcpy(windo_titl, (_maccur_pgm_name == NULL ||
*_maccur_pgm_name == '\0') ?
"Curses" : _maccur_pgm_name);
if ((the_windo = NewWindow(nil, &windo_rect,
CtoPstr(windo_titl), TRUE,
noGrowDocProc, (WindowPtr)-1L,
FALSE, (long)nil)) == nil)
{
maccur_alert_msg("Could not initialize program window!");
ExitToShell();
}
SetPort(the_windo);
if (font_num != 0)
TextFont(font_num);
TextSize(_maccur_font_size);
GetFontInfo(&fnt_info);
if (charwid_pix != fnt_info.widMax ||
rowheight_pix != fnt_info.ascent + fnt_info.descent + fnt_info.leading)
{
charwid_pix = fnt_info.widMax;
rowheight_pix = fnt_info.ascent + fnt_info.descent + fnt_info.leading;
SizeWindow(the_windo, X_PIX_WIN, Y_PIX_WIN, TRUE);
}
/* Could check if bold-condense is same size as normal to allow/dissallow bold mode? */
ShowWindow(the_windo);
}
/********
**
** maccur_init_menus: Set up menu bar (for now, only the apple menu).
**
**
********/
static void maccur_init_menus(void)
{
Handle menu_bar_hndl;
MenuHandle menu_hndl;
char about_str[128];
if ((menu_bar_hndl = GetNewMBar(MENU_RES_ID)) != NULL)
{
SetMenuBar(menu_bar_hndl);
menu_hndl = GetMHandle(MENU_RES_ID);
if (_maccur_about_res_id != 0)
{
sprintf(about_str, "About %s...", _maccur_pgm_name);
SetItem(menu_hndl, 1, CtoPstr(about_str));
maccur_about_mitm = 1;
}
else
{
DelMenuItem(menu_hndl, 1);
maccur_about_mitm = 0;
}
AddResMenu(menu_hndl, 'DRVR');
DrawMenuBar();
maccur_has_menu = TRUE;
}
else maccur_has_menu = FALSE;
}
/********
**
** maccur_draw_text_line: Write a single line of text to window. Input text is
** type chtype, with attribute info.
**
**
********/
static void maccur_draw_text_line(
chtype *line_ptr, /* -R- Pointer to text to write. */
int n, /* -R- Number of characters. */
int row, /* -R- Start at what row on screen (first row is 0). */
int col /* -R- Start at what column on screen (first col is 0). */
) {
int i, first_pass_flag, j, attr, previous_attr, txt_face;
char out_str[MAX_OUT_STRSEG];
SetPort(the_windo);
MoveTo(COL_TO_PIX(col), ROW_TO_PIX(row));
for (i = 0, first_pass_flag = TRUE; i < n; ) /* Loop until string is written, writing it in segments */
{ /* that all have the same attribute. */
for (j = 0, attr = (*(line_ptr + i) & A_ATTRIBUTES);
i < n && j < MAX_OUT_STRSEG && attr == (*(line_ptr + i) & A_ATTRIBUTES);
i++, j++)
out_str[j] = (*(line_ptr + i) & A_CHARTEXT);
if (attr != previous_attr || first_pass_flag) /* Determine/set attribute for this segment... */
{
if (attr & A_REVERSE || attr & A_STANDOUT) /* Should do standout w/ hilite? */
TextMode(notSrcCopy);
else
TextMode(srcCopy);
txt_face = normal;
if (attr & A_UNDERLINE)
txt_face |= underline;
if (attr & A_BOLD) /* It is assument that bold condense is same size as normal. */
txt_face |= (bold | condense);
TextFace(txt_face);
previous_attr = attr;
}
DrawText(out_str, 0, j);
first_pass_flag = FALSE;
}
}
/********
**
** maccur_flash_cursor: Flash cursor.
**
**
********/
static void maccur_flash_cursor(void)
{
InvertRect(&cursor_rect);
cursor_inverted = !cursor_inverted;
}
/********
**
** maccur_unflash_cursor: Unhighlight cursor if it is highlighted.
**
**
********/
static void maccur_unflash_cursor(void)
{
if (cursor_inverted) maccur_flash_cursor();
}
/********
**
** maccur_set_cursor: Set cursor_rect to reflect current cursor position.
** Before moving it, un-invert it if necessary (based on cursor_inverted flag).
**
**
********/
static void maccur_set_cursor(
int row, /* -R- Row for cursor. */
int col /* -R- Column for cursor. */
) {
if (cursor_inverted) maccur_flash_cursor();
show_cursor_flag = TRUE;
row = MIN(row, _maccur_lines - 1);
col = MIN(col, _maccur_cols - 1);
cursor_rect.bottom = ROW_TO_PIX(row) + fnt_info.descent + fnt_info.leading;
cursor_rect.right = COL_TO_PIX(col + 1);
cursor_rect.top = cursor_rect.bottom - rowheight_pix;
cursor_rect.left = COL_TO_PIX(col);
}
/********
**
** maccur_mouse_down_evnt: Do something about mouse down event. All that
** is handled is the apple menu, dragging the window, and system clicks.
**
**
********/
static void maccur_mouse_down_evnt(
EventRecord *event_ptr /* -R- The event details. */
) {
WindowPtr wndo_ptr;
MenuHandle apl_menu_hndl;
Str255 nam;
long menu_choice;
short wnd_part, menu_id, menu_itm, num;
wnd_part = FindWindow(event_ptr->where, &wndo_ptr);
switch (wnd_part)
{
case inMenuBar:
if ((menu_choice = MenuSelect(event_ptr->where)) != 0)
{
menu_id = HiWord(menu_choice);
menu_itm = LoWord(menu_choice);
if (menu_id == MENU_RES_ID)
{
if (menu_itm == maccur_about_mitm) /* See if this is about... */
{
if (NoteAlert(_maccur_about_res_id, NULL) == -1)
SysBeep(1);
}
else
{
apl_menu_hndl = GetMHandle(MENU_RES_ID); /* If not, pass it on. */
GetItem(apl_menu_hndl, menu_itm, nam);
num = OpenDeskAcc(nam);
}
}
HiliteMenu(0);
}
break;
case inSysWindow:
SystemClick(event_ptr, wndo_ptr);
break;
case inContent:
break;
case inDrag:
DragWindow(wndo_ptr, event_ptr->where,
&screenBits.bounds);
break;
}
}
/********
**
** maccur_event_loop: Main event loop. Argument indicates whether it is to
** return due to a null event or due to a key stroke.
**
** Returns:
** Reason for return (null or keystroke).
**
**
********/
static int maccur_event_loop(
int until_flags
) {
EventRecord event;
int i;
long sleep;
char c;
if (TST_BIT(until_flags, MACCUR_RETURN_ON_CHAR_BIT)) /* If waiting for a character, don't need a lot of CPU. */
{
if (in_background_flag) /* Don't need any in background. */
sleep = LONG_MAX;
else sleep = FLASH_TICKS; /* Just need enough to flash cursor in foreground. */
}
else /* If not waiting for a character, try to give up some time. */
{ /* but maybe not a lot. */
if (in_background_flag)
sleep = _maccur_bg_sleep_ticks;
else sleep = _maccur_fg_sleep_ticks;
}
while (1) /* Loop until return condition is met. */
{
if (WaitNextEvent(everyEvent, &event, sleep, nil))
{
switch (event.what)
{
case kHighLevelEvent:
AEProcessAppleEvent(&event);
break;
case mouseDown:
if (maccur_has_menu)
maccur_mouse_down_evnt(&event);
break;
case keyDown:
case autoKey:
if ((event.modifiers & cmdKey) != 0) /* Ignore all command keys except CMD-. */
{
if ((event.message & charCodeMask) == '.') /* This may exit right away or simulate a control-C interrupt. */
{
switch (_maccur_handle_break_option)
{
case MACCUR_EXIT_ON_BREAK:
ExitToShell();
break;
case MACCUR_SIGNAL_BREAK:
raise(SIGINT);
break;
}
}
else break;
}
if (typeahead_cnt >= MAX_TYPEAHEAD) /* Other keystrokes go into typeahead (if there is room). */
SysBeep(1); /* Typeahead buf is circular. */
else
{
typebuf[typeahead_indx % MAX_TYPEAHEAD].msg = event.message;
typebuf[typeahead_indx % MAX_TYPEAHEAD].mod = event.modifiers;
}
typeahead_indx++;
typeahead_cnt++;
if (TST_BIT(until_flags, MACCUR_RETURN_ON_CHAR_BIT))/* Return if keystroke was what was wanted. */
return MACCUR_RETURN_ON_CHAR_BIT;
break;
case updateEvt:
BeginUpdate((WindowPtr)(event.message));
EraseRect(&cursor_rect); /* This may be unnecessary??? */
for (i = 0; i < _maccur_lines; i++) /* Redraw the screen. */
maccur_draw_text_line(screen_char_arry + i * _maccur_cols,
_maccur_cols, i, 0);
cursor_inverted = FALSE;
EndUpdate((WindowPtr)(event.message));
break;
case osEvt: /* Switch background/foreground. */
if ((event.message & suspendResumeMessage) == resumeFlag)
in_background_flag = FALSE;
else
{
in_background_flag = TRUE;
maccur_unflash_cursor(); /* Turn cursor off in the background. */
}
break;
}
}
else if (TST_BIT(until_flags, MACCUR_RETURN_ON_IDLE_BIT)) /* If just letting CPU run, this is the cue to split. */
return MACCUR_RETURN_ON_IDLE_BIT;
if (!in_background_flag && show_cursor_flag && /* See if its time to flash the cursor. */
event.when - last_flash_when > FLASH_TICKS)
{
if (event.what != osEvt)
maccur_flash_cursor();
last_flash_when = event.when;
}
}
}
/****
* The following "keypad map" maps various non-ascii keystrokes to
* their curses KEY_xxx equivalents. This could be made global so
* that user supplied replacements could be linked in (but who would
* want to go to all that trouble).
****/
#define KEYMAP_BASE 0x33 /* Key number of first key to translate. */
#define KEYMAP_TOP (KEYMAP_BASE + sizeof(dflt_keypad_map)/sizeof(KEYPAD_MAP))
#define KEYMAP_NOCODE 0 /* If this is key translation, return ascii code for that key. */
typedef struct keypad_map_strct { /* Determine what to do with key/modifier: */
chtype basic_code; /* This is translation of unmodified key. */
chtype shift_code; /* Translation of key with shift. */
chtype opt_code; /* Translation of key with option. */
chtype shift_opt_code; /* Translation of key with shift-option. */
} KEYPAD_MAP;
static KEYPAD_MAP dflt_keypad_map[] = {
/* 33 delete */ {KEY_BACKSPACE, KEY_BACKSPACE, KEY_BACKSPACE, KEY_BACKSPACE},
/* 34 */ {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 35 */ {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 36 */ {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 37 */ {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 38 */ {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 39 */ {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 3A */ {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 3B */ {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 3C */ {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 3D */ {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 3E */ {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 3F */ {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 40 */ {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 41 KP-. */ {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 42 rt arrow (Mac +) */ {KEY_RIGHT, KEY_SRIGHT, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 43 KP-* */ {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 44 */ {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 45 KP-+ */ {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 46 left arrow (Mac +) */ {KEY_LEFT, KEY_SLEFT, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 47 clear */ {KEY_CLEAR, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 48 down arrow (Mac +) */ {KEY_DOWN, KEY_NPAGE, KEY_END, KEYMAP_NOCODE},
/* 49 */ {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 4A */ {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 4B KP-/ */ {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 4C enter */ {KEY_ENTER, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 4D up arrow (Mac +) */ {KEY_UP, KEY_PPAGE, KEY_HOME, KEYMAP_NOCODE},
/* 4E KP-- */ {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 4F */ {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 50 */ {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 51 KP-= */ {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 52 KP-0 */ {KEYMAP_NOCODE, KEYMAP_NOCODE, KEY_F(0), KEY_F(10)},
/* 53 KP-1 */ {KEY_C1, KEYMAP_NOCODE, KEY_F(1), KEY_F(11)},
/* 54 KP-2 */ {KEY_DOWN, KEYMAP_NOCODE, KEY_F(2), KEY_F(12)},
/* 55 KP-3 */ {KEY_C3, KEYMAP_NOCODE, KEY_F(3), KEY_F(13)},
/* 56 KP-4 */ {KEY_LEFT, KEYMAP_NOCODE, KEY_F(4), KEY_F(14)},
/* 57 KP-5 */ {KEY_B2, KEYMAP_NOCODE, KEY_F(5), KEY_F(15)},
/* 58 KP-6 */ {KEY_RIGHT, KEYMAP_NOCODE, KEY_F(6), KEY_F(16)},
/* 59 KP-7 */ {KEY_A1, KEYMAP_NOCODE, KEY_F(7), KEY_F(17)},
/* 5A */ {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 5B KP-8 */ {KEY_UP, KEYMAP_NOCODE, KEY_F(8), KEY_F(18)},
/* 5C KP-9 */ {KEY_A3, KEYMAP_NOCODE, KEY_F(9), KEY_F(19)},
/* 5D */ {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 5E */ {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 5F */ {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 60 F5 */ {KEY_F(5), KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 61 F6 */ {KEY_F(6), KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 62 F7 */ {KEY_F(7), KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 63 F3 */ {KEY_F(3), KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 64 F8 */ {KEY_F(8), KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 65 F9 */ {KEY_F(9), KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 66 */ {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 67 F11 */ {KEY_F(11), KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 68 */ {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 69 F13 */ {KEY_F(13), KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 6A */ {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 6B F14 */ {KEY_F(14), KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 6C */ {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 6D F10 */ {KEY_F(10), KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 6E */ {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 6F F12 */ {KEY_F(12), KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 70 */ {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 71 F15 */ {KEY_F(15), KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 72 ins */ {KEY_IC, KEY_IL, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 73 home */ {KEY_HOME, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 74 pgup */ {KEY_PPAGE, KEY_SR, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 75 fwd del */ {KEY_DC, KEY_DL, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 76 F4 */ {KEY_F(4), KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 77 end */ {KEY_END, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 78 F2 */ {KEY_F(2), KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 79 pgdn */ {KEY_NPAGE, KEY_SF, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 7A F1 */ {KEY_F(1), KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 7B left arrow */ {KEY_LEFT, KEY_SLEFT, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 7C rt arrow */ {KEY_RIGHT, KEY_SRIGHT, KEYMAP_NOCODE, KEYMAP_NOCODE},
/* 7D down arrow */ {KEY_DOWN, KEY_NPAGE, KEY_END, KEYMAP_NOCODE},
/* 7E up arrow */ {KEY_UP, KEY_PPAGE, KEY_HOME, KEYMAP_NOCODE},
/* 7F */ {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE}
};
/********
**
** maccur_key_trans: Return curses key code based on keystroke event.
** If key has no entry in translation table, or entry is KEYMAP_NOCODE,
** return ascii value.
**
** Returns:
** Character translation of keystroke (type chtype).
**
**
********/
static chtype maccur_key_trans(
KEY_EVENT *ch_evnt_ptr,
int keypad_enabled_flag
) {
chtype c, c_ascii, key;
c_ascii = ch_evnt_ptr->msg & charCodeMask;
key = (ch_evnt_ptr->msg & keyCodeMask) >> 8;
if (keypad_enabled_flag && key >= KEYMAP_BASE && key < KEYMAP_TOP)
{
if ((ch_evnt_ptr->mod & shiftKey) && (ch_evnt_ptr->mod & optionKey))
c = (dflt_keypad_map + (key - KEYMAP_BASE))->shift_opt_code;
else if ((ch_evnt_ptr->mod & shiftKey))
c = (dflt_keypad_map + (key - KEYMAP_BASE))->shift_code;
else if ((ch_evnt_ptr->mod & optionKey))
c = (dflt_keypad_map + (key - KEYMAP_BASE))->opt_code;
else
c = (dflt_keypad_map + (key - KEYMAP_BASE))->basic_code;
if (c == KEYMAP_NOCODE) c = c_ascii;
}
else
{
if (key == 0x4C) c = '\n'; /* Give the keypad enter key a better ascii translation. */
else c = c_ascii;
}
return c;
}
/********
**
** maccur_flush_typeahead: Flush the typeahead buffer.
**
**
********/
void maccur_flush_typeahead(
void
) {
typeahead_indx = typeahead_cnt = outchar_indx = 0;
}
/********
**
** maccur_init: Entry point for initalization. Sets LINES and COLS
** to the size of the window that is opened up.
**
** Returns:
** TRUE if initialization is successful, else FALSE.
**
**
********/
bool maccur_init(void)
{
int i, screen_chars;
screen_chars = _maccur_cols * _maccur_lines;
if (screen_char_arry == NULL) /* Allow for multiple calls to this routine (especially */
{ /* implicit ones for fake stdio). */
maccur_init_toolbox();
maccur_init_event();
maccur_init_window();
maccur_init_menus();
LINES = _maccur_lines;
COLS = _maccur_cols;
if ((screen_char_arry = malloc(screen_chars * sizeof(chtype))) == NULL)
return FALSE;
}
for (i = 0; i < screen_chars; i++) /* Blank the screen. */
*(screen_char_arry + i) = ' ';
return TRUE;
}
/********
**
** maccur_refresh: Refresh the screen for a curses window.
**
** Returns:
** ERR on error, else OK.
**
**
********/
int maccur_refresh(WINDOW *win, bool outflag)
{
static int next_cursor_col = 0; /* Save cursor position for next window refresh. */
static int next_cursor_row = 0; /* (in case there are multiple calls before refresh and some have leaveok TRUE). */
static int window_current_flag; /* Set to true when window is updated from saved image. */
static int cursor_enabled_flag; /* Set to true if at least one window contributing to screen has a cursor. */
int i, mov_size, maxx, maxy;
chtype *src_ptr, *dst_ptr;
/* Your comment here */
if (screen_char_arry == NULL) return ERR; /* Initialization has not been done (bad). */
if (win) /* If window was passed, transfer chars from it. */
{
if (win->_begy < _maccur_lines && win->_begx < _maccur_cols)
{
dst_ptr = screen_char_arry + (win->_begy * _maccur_cols) +
win->_begx;
if (win->_flags & _ISPAD)
{
maxx = win->_pmap_maxx - win->_pmap_orgx; /* For pads, get # rows and columns to display. */
maxy = win->_pmap_maxy - win->_pmap_orgy;
src_ptr = win->_y + /* Point to 1st displayed character in pad. */
((win->_pmap_orgy * win->_xdim) +
win->_pmap_orgx);
}
else
{
maxx = win->_maxx;
maxy = win->_maxy;
src_ptr = win->_y;
}
mov_size = MIN(maxx, _maccur_cols - win->_begx) *
sizeof(chtype);
for (i = 0; i < maxy && i + win->_begy < _maccur_lines; /* Copy text from window to screen image. */
i++, dst_ptr += _maccur_cols,
src_ptr += win->_xdim)
memcpy(dst_ptr, src_ptr, mov_size);
}
if (!win->_leave) /* If cursor is not left off, */
{
next_cursor_row = _CURS_CURSOR_SCREEN_ROW(win); /* Save its position. */
next_cursor_col = _CURS_CURSOR_SCREEN_COL(win);
cursor_enabled_flag = TRUE; /* It will be enabled on next screen update. */
}
else if (window_current_flag) /* If this is 1st refresh after update and cursor */
cursor_enabled_flag = FALSE; /* disabled, indicate that. Subsequent refreshes */
else cursor_enabled_flag = cursor_enabled_flag || FALSE; /* or into flag so if cursor is enabled once it is shown. */
window_current_flag = FALSE;
}
if (outflag) /* If actual screen update is to be done... */
{
for (i = 0; i < _maccur_lines; i++) /* Draw the characters. */
maccur_draw_text_line(screen_char_arry + i * _maccur_cols,
_maccur_cols, i, 0);
if (cursor_enabled_flag)
{
cursor_inverted = FALSE; /* Window was completely re-written, so cursor is gone. */
maccur_set_cursor(next_cursor_row, next_cursor_col);
}
else show_cursor_flag = FALSE;
window_current_flag = TRUE;
}
return OK;
}
/********
**
** maccur_end: Exit curses mode.
**
** Returns:
** OK.
**
**
********/
bool maccur_end(void)
{
void maccur_noncurse_mode_scroll(void);
maccur_noncurse_mode_scroll(); /* Scroll screen up a line and position cursor at bottom. */
direct_curs_pos_row = _maccur_lines - 1;
direct_curs_pos_col = 0;
maccur_set_cursor(direct_curs_pos_row, direct_curs_pos_col);
return OK;
}
/********
**
** maccur_beep: Beep or flash the screen.
**
**
********/
void maccur_beep(
int flash_flag /* -R- TRUE to flash instead of beep. */
) {
if (flash_flag)
SysBeep(0);
else
SysBeep(1);
}
/********
**
** maccur_kbinp: Take a single character input.
**
** Returns:
** Character read, or ERR if no character ready or error.
**
**
********/
int maccur_kbinp(WINDOW *win, bool raw, bool cbreak)
{
if (typeahead_cnt == 0 && win->_nodelay) /* If caller is in a hurry don't make 'em wait */
return ERR;
if (typeahead_cnt == 0) /* If need to wait for input... */
{
maccur_set_cursor(_CURS_CURSOR_SCREEN_ROW(win), /* Set cursor to current input position. */
_CURS_CURSOR_SCREEN_COL(win)); /* (this will also un-invert it). */
if (win->_leave) /* If cursor is to be left off, set flag to false. */
show_cursor_flag = FALSE;
maccur_event_loop(SET_BIT(MACCUR_RETURN_ON_CHAR_BIT));
}
if (typeahead_cnt > 0) /* There should be something to return now, so do it... */
{
typeahead_cnt--;
if (outchar_indx >= MAX_TYPEAHEAD) outchar_indx = 0;
return maccur_key_trans(typebuf + outchar_indx++, win->_use_keypad);
}
return ERR;
}
/********
**
** maccur_alert_text: Display a string in an alert box.
** Trim white space and newlines from beginning and end of string first.
**
**
********/
static void maccur_alert_text(
char *txt
) {
static char buf[256];
int len;
while (isspace(*txt)) /* Strip off leading white space. */
txt++;
len = strlen(txt);
while (len > 0 && isspace(*(txt + len - 1))) /* Strip off trailing white space. */
len--;
if (len > 255) len = 255;
buf[0] = len; /* Make it a pascal string. */
memcpy(buf + 1, txt, len);
ParamText((ConstStr255Param) buf, NULL, NULL, NULL);
if (CountResources('ALRT') == 0)
return;
Alert(ALERT_RSRC_ID, NULL); /* Display as an alert. */
}
/********
**
** maccur_alert_msg: Display a string as an alert message, after
** formatting it with sprintf.
**
**
********/
void maccur_alert_msg(
char *fmt,
...
) {
va_list args;
int rtn;
if (screen_char_arry == NULL)
maccur_init();
va_start(args, fmt);
rtn = vsprintf(_curses_prntw, fmt, args);
va_end(args);
if (rtn < 0) strcpy(_curses_prntw, "Error in curses");
maccur_alert_text(_curses_prntw);
}
/********
**
** maccur_cpu_share: Call the event manager so CPU time can be shared.
**
**
********/
void maccur_cpu_share(void)
{
maccur_event_loop(SET_BIT(MACCUR_RETURN_ON_IDLE_BIT));
}
/* ************************************************************************** */
/* STDIO emulation */
/* */
/* The following routines can be used to emulate standard io calls to stdin */
/* and stdout, placing the output in the curses window. */
/* */
/* ************************************************************************** */
/********
**
** maccur_noncurse_mode_scroll: Scroll the screen up a line.
**
**
********/
static void maccur_noncurse_mode_scroll(void)
{
int i;
chtype *scrn_ptr;
memmove(screen_char_arry, screen_char_arry + _maccur_cols, /* Scroll it up. */
_maccur_cols * (_maccur_lines - 1) * sizeof(chtype));
scrn_ptr = screen_char_arry + ((_maccur_lines - 1) * _maccur_cols);
for (i = 0; i < _maccur_cols; i++) /* Clear bottom line. */
*(scrn_ptr + i) = ' ';
for (i = 0; i < _maccur_lines; i++)
maccur_draw_text_line(screen_char_arry + i * _maccur_cols,
_maccur_cols, i, 0);
cursor_inverted = FALSE;
}
/********
**
** maccur_noncurse_mode_show_str: Display a string on the screen.
** Wrap strings that are too long and expand tabs.
**
**
********/
static void maccur_noncurse_mode_show_str(
char *str, /* -R- String to display. */
int *row_pos_ptr, /* -M- Passed as row to start string, updated to row of end of string. */
int *col_pos_ptr, /* -M- Passed as column to start string, updated to column of end of string. */
int *scroll_cnt_ptr, /* -W- Return number of lines up the screen was scrolled. */
bool show_str_flag, /* -R- TRUE to display string, FALSE to just return cursor position at end of string. */
bool add_newline_flag, /* -R- True if extra newline should be added after string is displayed. */
bool clear_to_eos_flag /* -R- True to clear all of screen following displayed string. */
) {
int nchars, char_pos, row_pos, col_pos, i, n_to_show,
end_col_pos, move_down_flag;
chtype *scrn_ptr;
char *out_ptr, *cp;
if (scroll_cnt_ptr != NULL)
*scroll_cnt_ptr = 0;
nchars = strlen(str);
char_pos = 0;
row_pos = *row_pos_ptr;
col_pos = *col_pos_ptr;
out_ptr = str;
while (nchars > 0) /* Loop while there are characters to write out. */
{
if (col_pos >= _maccur_cols)
{
col_pos = 0;
row_pos++;
}
if (show_str_flag && row_pos >= _maccur_lines) /* If writing position is past end of screen, scroll. */
{
maccur_noncurse_mode_scroll();
if (scroll_cnt_ptr != NULL) (*scroll_cnt_ptr)++;
row_pos = _maccur_lines - 1;
}
n_to_show = MIN(_maccur_cols - col_pos, nchars); /* Determine how many chars to put in this line: */
if ((cp = strchr(out_ptr, '\n')) != NULL) /* up to end of line, up to end of string, */
n_to_show = MIN(n_to_show, cp - out_ptr); /* up to next newline, or up to tab. */
if ((cp = strchr(out_ptr, '\t')) != NULL)
n_to_show = MIN(n_to_show, cp - out_ptr);
if (show_str_flag)
{
scrn_ptr = screen_char_arry + (row_pos * _maccur_cols) +
col_pos;
for (i = 0; i < n_to_show; i++) /* Copy the characters out. */
*(scrn_ptr + i) = *(out_ptr + i);
}
col_pos += n_to_show;
move_down_flag = FALSE;
if (*(out_ptr + n_to_show) == '\n') /* If newline encountered, blank out rest of line */
{ /* and position to beginning of next. */
if (show_str_flag)
{
scrn_ptr = screen_char_arry + (row_pos * _maccur_cols);
while (col_pos < _maccur_cols)
*(scrn_ptr + col_pos++) = ' ';
}
n_to_show++; /* Skip over the '\n' */
move_down_flag = TRUE;
}
else if (*(out_ptr + n_to_show) == '\t') /* For a tab, blank up to the next tab stop. */
{
end_col_pos = col_pos + (_curses_tab_wid - /* Blank fwd until col_pos becomes multiple of tab wid. */
col_pos % _curses_tab_wid);
end_col_pos = MIN(end_col_pos, _maccur_cols); /* But don't wrap over into next line. */
if (show_str_flag)
{
scrn_ptr = screen_char_arry + (row_pos * _maccur_cols);
while (col_pos < end_col_pos)
*(scrn_ptr + col_pos++) = ' ';
}
col_pos = end_col_pos;
n_to_show++; /* Skip over the '\t' */
}
if (show_str_flag)
maccur_draw_text_line(screen_char_arry + /* Redraw the modified line. */
row_pos * _maccur_cols,
_maccur_cols, row_pos, 0);
if (move_down_flag)
{
col_pos = 0; /* Move to next line. */
row_pos++;
}
if (show_str_flag && row_pos >= _maccur_lines) /* If writing position is past end of screen, scroll. */
{
maccur_noncurse_mode_scroll();
if (scroll_cnt_ptr != NULL) (*scroll_cnt_ptr)++;
row_pos = _maccur_lines - 1;
}
out_ptr += n_to_show;
nchars -= n_to_show;
}
if (add_newline_flag || clear_to_eos_flag) /* If extra newline is to be added after string output or */
{ /* or screen is to be cleared up to end of screen. */
if (show_str_flag)
{
int last_row, i_rw;
if (clear_to_eos_flag) /* Whether new line or cleareos, will be clearing rest */
last_row = _maccur_lines; /* of current line and possibly others. */
else last_row = row_pos + 1;
for (i_rw = row_pos; i_rw < last_row; i_rw++) /* Do next line or a bunch depending on clear_to_eos_flag. */
{
scrn_ptr = screen_char_arry + (i_rw * _maccur_cols);
for (i = (i_rw == row_pos ? col_pos : 0); /* Clear the line. */
i < _maccur_cols; i++)
*(scrn_ptr + i) = ' ';
maccur_draw_text_line(screen_char_arry + /* Redraw the modified line. */
i_rw * _maccur_cols,
_maccur_cols, i_rw, 0);
}
}
if (add_newline_flag) /* If actually echoing a newline. */
{
col_pos = 0;
row_pos++;
if (show_str_flag && row_pos >= _maccur_lines) /* Scroll of necessary. */
{
maccur_noncurse_mode_scroll();
if (scroll_cnt_ptr != NULL) (*scroll_cnt_ptr)++;
row_pos = _maccur_lines - 1;
} /* (this automatically clears the last line of screen). */
}
}
*row_pos_ptr = row_pos;
*col_pos_ptr = col_pos;
}
/********
**
** maccur_noncurse_mode_getstr: Input a string, echoing input to screen,
** allowing editing with left/right arrows, delete key, clear key
** (or ctrl-u) to clear input, ctrl-e to move to end of input,
** ctrl-d to return EOF. Special single character mode does away
** with most special line editing, and returns with the single char (ala getchar).
**
** Returns:
** Number of characters in, or EOF if CTRL-D entered.
**
**
********/
static int maccur_noncurse_mode_getstr(
char *str, /* -W- Put the string read here. */
int max_chars, /* -R- Size of above string (or -1 if unknown). */
int single_char_flag /* -R- True if this is call for a single character. */
) {
int begin_at, nchars, pos, key, c_ascii, cleareos_flag,
redisplay_flag, disp_pos, disp_row, disp_col, scroll_cnt,
rtn_val, string_ended_flag, add_newline_flag, save_char;
begin_at = (direct_curs_pos_row * _maccur_cols) + /* Remember initial cursor position. */
direct_curs_pos_col;
nchars = pos = rtn_val = 0;
*str = '\0';
string_ended_flag = FALSE;
while (!string_ended_flag)
{
redisplay_flag = FALSE;
cleareos_flag = FALSE;
add_newline_flag = FALSE;
if (typeahead_cnt == 0) /* If need to wait for input... */
{
disp_row = begin_at/_maccur_cols;
disp_col = begin_at % _maccur_cols;
save_char = *(str + pos);
*(str + pos) = '\0';
maccur_noncurse_mode_show_str(str, /* Measure string to determine cursor position at */
&disp_row, &disp_col, /* input point (there might be tabs). */
NULL, FALSE, FALSE, FALSE);
*(str + pos) = save_char;
if (disp_col >= _maccur_cols) /* Move cursor to next line if it is past end of a line. */
{
disp_col = 0;
disp_row++;
}
if (disp_row >= _maccur_lines) /* Scroll if cursor off screen. */
{
maccur_noncurse_mode_scroll();
disp_row = _maccur_lines - 1;
begin_at -= _maccur_cols;
}
maccur_set_cursor(disp_row, disp_col); /* Set cursor to current input position. */
maccur_event_loop(SET_BIT(MACCUR_RETURN_ON_CHAR_BIT)); /* Get some text. */
maccur_unflash_cursor();
}
if (typeahead_cnt > 0) /* There should be at least one keystroke available. */
{
typeahead_cnt--;
if (outchar_indx >= MAX_TYPEAHEAD) outchar_indx = 0;
c_ascii = (typebuf + outchar_indx)->msg & charCodeMask;
key = ((typebuf + outchar_indx)->msg & keyCodeMask) >> 8;
outchar_indx++;
switch (key) /* See if key has special meaning. */
{
case 0x7D: /* Up and down arrows (Mac plus and II). */
case 0x7E: /* All ignored. */
case 0x4D:
case 0x48:
SysBeep(1);
break;
case 0x7C: /* Right arrow (Mac II). */
case 0x42: /* (Mac plus). */
if (pos < nchars)
pos++;
else SysBeep(1);
break;
case 0x7B: /* Left arrow (Mac II). */
case 0x46: /* (Mac plus). */
if (pos > 0)
pos--;
else SysBeep(1);
break;
case 0x33: /* DELETE key. */
if (pos > 0)
{
if (pos < nchars)
memmove(str + (pos - 1), str + pos, nchars - pos);
*(str + --nchars) = '\0';
pos--;
redisplay_flag = TRUE;
cleareos_flag = TRUE;
}
else SysBeep(1);
break;
case 0x47: /* CLEAR key. */
if (single_char_flag) SysBeep(1); /* Don't let getchar user think CLEAR means anything. */
nchars = pos = 0;
*str = '\0';
redisplay_flag = TRUE;
cleareos_flag = TRUE;
break;
case 0x24: /* RETURN key. */
case 0x4C: /* ENTER key. */
if (single_char_flag) /* Single character mode will allow \n as a return value. */
{
*str = '\n';
*(str + 1) = '\0';
nchars = 1;
}
else add_newline_flag = TRUE; /* Don't return newline in string, so set flag to echo it. */
string_ended_flag = TRUE;
redisplay_flag = TRUE; /* Redisplay it to echo newline. */
rtn_val = pos = nchars;
break;
default:
if (c_ascii == 4) /* Control-D (return EOF). */
{
rtn_val = EOF;
string_ended_flag = TRUE;
}
else if (!single_char_flag && c_ascii == 5) /* Control-E (move to end of input text). */
{
pos = nchars;
}
else if (!single_char_flag && c_ascii == 21) /* Control-U (same as CLEAR) */
{
nchars = pos = 0;
*str = '\0';
redisplay_flag = TRUE;
cleareos_flag = TRUE;
}
else /* Get here if its just a regular old ascii value. */
{
if (max_chars >= 0 && nchars >= max_chars - 1)
SysBeep(1);
else
{
if (pos < nchars)
memmove(str + (pos + 1), str + pos, nchars - pos);
*(str + pos++) = c_ascii;
*(str + ++nchars) = '\0';
redisplay_flag = TRUE;
}
}
break;
}
if (redisplay_flag) /* If something has happened necesitating a redraw, do it. */
{
disp_pos = MAX(0, pos - 1); /* Just redraw from current position on. */
disp_row = begin_at/_maccur_cols; /* But first measure to find start position. */
disp_col = begin_at % _maccur_cols;
save_char = *(str + disp_pos);
*(str + disp_pos) = '\0';
maccur_noncurse_mode_show_str(str,
&disp_row, &disp_col,
NULL, FALSE, FALSE, FALSE);
*(str + disp_pos) = save_char;
maccur_noncurse_mode_show_str(str + disp_pos,
&disp_row, &disp_col,
&scroll_cnt, TRUE,
add_newline_flag, cleareos_flag);
begin_at -= scroll_cnt * _maccur_cols;
}
if (single_char_flag && nchars > 0 && !string_ended_flag)
{
string_ended_flag = TRUE;
rtn_val = nchars;
}
}
}
direct_curs_pos_row = disp_row; /* Leave cursor where last update put it. */
direct_curs_pos_col = disp_col;
return rtn_val;
}
/********
**
** maccur_printf: Equivalent to printf.
**
** Returns:
** Results of vsprintf.
**
**
********/
int maccur_printf(
char *fmt,
...
) {
va_list args;
int rtn;
if (screen_char_arry == NULL)
maccur_init();
va_start(args, fmt);
rtn = vsprintf(_curses_prntw, fmt, args);
va_end(args);
if (rtn < 0) return rtn;
maccur_noncurse_mode_show_str(_curses_prntw, &direct_curs_pos_row,
&direct_curs_pos_col, NULL, TRUE,
FALSE, FALSE);
if (_maccur_io_sleep_dvsr > 0 && ++cpu_share_rot_cnt >= _maccur_io_sleep_dvsr)
{
maccur_cpu_share();
cpu_share_rot_cnt = 0;
}
return rtn;
}
/********
**
** maccur_puts: Equivalent to puts.
**
** Returns:
** 0 (success).
**
**
********/
int maccur_puts(
char *str
) {
if (screen_char_arry == NULL)
maccur_init();
maccur_noncurse_mode_show_str(str, &direct_curs_pos_row,
&direct_curs_pos_col, NULL, TRUE,
TRUE, FALSE);
if (_maccur_io_sleep_dvsr > 0 && ++cpu_share_rot_cnt >= _maccur_io_sleep_dvsr)
{
maccur_cpu_share();
cpu_share_rot_cnt = 0;
}
return 0;
}
/********
**
** maccur_putchar: Equivalent to putchar.
**
** Returns:
** Character printed.
**
**
********/
int maccur_putchar(
char c
) {
char str[2];
if (screen_char_arry == NULL)
maccur_init();
str[0] = c;
str[1] = '\0';
maccur_noncurse_mode_show_str(str, &direct_curs_pos_row,
&direct_curs_pos_col, NULL, TRUE,
FALSE, FALSE);
if (_maccur_io_sleep_dvsr > 0 && ++cpu_share_rot_cnt >= _maccur_io_sleep_dvsr)
{
maccur_cpu_share();
cpu_share_rot_cnt = 0;
}
return c;
}
/********
**
** maccur_scanf: Equivalent to scanf. Uses THINK C's non-portable _vsscanf.
**
** Returns:
** Results of _vsscanf.
**
**
********/
int maccur_scanf(
char *fmt,
...
) {
va_list args;
int rtn;
if (screen_char_arry == NULL)
maccur_init();
maccur_noncurse_mode_getstr(_curses_prntw, _curses_prntw_size, FALSE);
va_start(args, fmt);
rtn = _vsscanf(_curses_prntw, fmt, args);
va_end(args);
return rtn;
}
/********
**
** maccur_gets: Equivalent to gets.
**
** Returns:
** Pointer to string argument (success).
**
**
********/
char *maccur_gets(
char *str
) {
if (screen_char_arry == NULL)
maccur_init();
if (maccur_noncurse_mode_getstr(str, -1, FALSE) == EOF)
return NULL;
return str;
}
/********
**
** maccur_getchar: Equivalent to getchar.
**
** Returns:
** Character read or EOF.
**
**
********/
int maccur_getchar(void)
{
char str[2];
int rtn;
if (screen_char_arry == NULL)
maccur_init();
if (maccur_noncurse_mode_getstr(str, 2, TRUE) == EOF)
rtn = EOF;
else
rtn = str[0];
return rtn;
}